package vcp.entity.utility;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

import vcp.entity.Lot;
import vcp.entity.Site;
import vcp.enums.Floor;

/**
 * 
 * @author VCP team
 *         <p>
 *         parking matrix class , holds lots for site
 */
public class ParkingMatrix implements Iterable <Lot>, Serializable
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 4666615100821205141L;

	private final Lot[] lots;
	private final Site parentSite;

	/**
	 * getter
	 * 
	 * @return parent site
	 */
	public Site getParentSite ()
	{
		return this.parentSite;
	}

	/**
	 * getter
	 * 
	 * @return number of floors
	 */
	public int getNumberOfFloor ()
	{
		return this.parentSite.getFloors();
	}

	/**
	 * getter
	 * 
	 * @return number of rows
	 */
	public int getNumberOfRows ()
	{
		return this.parentSite.getRows();
	}

	/**
	 * getter
	 * 
	 * @return number of columns
	 */
	public int getNumberOfColumns ()
	{
		return this.parentSite.getColumns();
	}

	/**
	 * constructor
	 * 
	 * @param site
	 */
	public ParkingMatrix ( Site site )
	{
		this.lots = new Lot[site.getCapacity()];
		this.parentSite = site;
	}

	/**
	 * adds new lot to matrix
	 * 
	 * @param lot
	 */
	public void addLot ( Lot lot )
	{
		int index = ( ( ( lot.getFloor() - 1 ) * this.parentSite.getRows() * this.parentSite.getColumns() ) + ( ( lot.getRow() - 1 ) * this.parentSite.getColumns() ) + lot.getColumn() ) - 1;
		this.lots[index] = lot;
	}

	/**
	 * clears matrix content
	 */
	public void clear ()
	{
		for ( int i = 0; i < this.lots.length; i ++ )
		{
			this.lots[i] = null;
		}
	}

	/**
	 * 
	 * @param floor
	 *            filter
	 * @return Lot iterator containing only lots from floor
	 */
	public Iterator <Lot> getFloorLots ( Floor floor )
	{
		Iterator <Lot> iterator = this.iterator();
		ArrayList <Lot> foundLots = new ArrayList <>();
		while ( iterator.hasNext() )
		{
			Lot lot = iterator.next();
			if ( lot.getFloor() == floor.getFloorNumber() )
			{
				foundLots.add(lot);
			}
		}

		return foundLots.iterator();
	}

	@Override
	public Iterator <Lot> iterator ()
	{
		return new ParkingMatrixIterator();
	}

	/**
	 * 
	 * @return new parking matrix data structure
	 */
	public ListIterator <Lot> listIterator ()
	{
		return new ParkingMatrixIterator();
	}

	/**
	 * 
	 * @author VCP team
	 *         <p>
	 *         parking matrix iterator class
	 */
	private class ParkingMatrixIterator implements ListIterator <Lot>
	{
		private int cursor;

		/**
		 * constructor
		 */
		private ParkingMatrixIterator ()
		{
			this.cursor = 0;
		}

		@Override
		public boolean hasNext ()
		{
			return this.cursor < ParkingMatrix.this.lots.length;
		}

		@Override
		public Lot next ()
		{
			Lot nextLot = ParkingMatrix.this.lots[this.cursor];
			this.cursor ++ ;
			return nextLot;
		}

		@Override
		public boolean hasPrevious ()
		{
			return this.cursor > - 1;
		}

		@Override
		public Lot previous ()
		{
			this.cursor -- ;
			Lot previousLot = ParkingMatrix.this.lots[this.cursor];
			return previousLot;
		}

		@Override
		public int nextIndex ()
		{
			return this.cursor < ParkingMatrix.this.lots.length
																? this.cursor
																: this.cursor - 1;
		}

		@Override
		public int previousIndex ()
		{
			return ( this.cursor - 1 ) >= 0
											? this.cursor - 1
											: 0;
		}

		@Override
		public void remove ()
		{
		}

		@Override
		public void set ( Lot e )
		{
		}

		@Override
		public void add ( Lot e )
		{
		}
	}
}
